package cn.com.dashihui.web.controller;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.shiro.authz.annotation.RequiresAuthentication;

import com.jfinal.aop.Clear;
import com.jfinal.aop.Duang;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;

import cn.com.dashihui.kit.DatetimeKit;
import cn.com.dashihui.pay.alipay.util.AlipayNotify;
import cn.com.dashihui.pay.alipay.util.AlipaySubmit;
import cn.com.dashihui.pay.wx.kit.HttpsRequest;
import cn.com.dashihui.pay.wx.kit.UtilKit;
import cn.com.dashihui.pay.wx.request.RefundReqData;
import cn.com.dashihui.pay.wx.response.RefundResData;
import cn.com.dashihui.web.base.BaseController;
import cn.com.dashihui.web.common.OrderCode;
import cn.com.dashihui.web.dao.Order;
import cn.com.dashihui.web.dao.OrderRefund;
import cn.com.dashihui.web.dao.OrderRefundAPIRecord;
import cn.com.dashihui.web.service.OrderRefundService;
import cn.com.dashihui.web.service.OrderService;

@RequiresAuthentication
public class OrderRefundController extends BaseController {
	//使用Duang.duang进行封装，使普通类具有事务的功能
	private OrderRefundService service = Duang.duang(OrderRefundService.class);
	private OrderService orderService = Duang.duang(OrderService.class);
	/**
	 * 退款单列表页面
	 */
	public void index(){
		render("index.jsp");
	}
	/**
	 * 获得退款单列表数据
	 */
	public void page(){
		int pageNum = getParaToInt(0, 1);
		int pageSize = getParaToInt("pageSize", PropKit.getInt("constants.pageSize"));
		//退款单编号
		String refundNum = getPara("refundNum");
		//订单编号
		String orderNum = getPara("orderNum");
		//下单时间范围
		String beginDate = getPara("beginDate");
		String endDate = getPara("endDate");
		//订单状态
		int state = getParaToInt("state",0);
		renderResult(0,service.findByPage(pageNum,pageSize,refundNum,orderNum,beginDate,endDate,state));
	}
	
	/**
	 * 审核不通过
	 */
	public void doRefuse(){
		String refundNum = getPara("refundNum");
		if(StrKit.isBlank(refundNum)){
			renderResult(1);
			return;
		}else{
			OrderRefund orderRefund = service.getOrderRefundByOrderNum(refundNum);
			if(orderRefund==null){
				renderResult(2);
				return;
			}else{
				String refuseReason = getPara("reason");
				//修改退款单状态为审核不通过，并记录原因
				if(Db.update("UPDATE t_bus_order_refund SET state=?,refuseReason=? WHERE refundNum=? AND state=?",OrderCode.RefundState.VERIFY_FAILED,refuseReason,refundNum,OrderCode.RefundState.VERIFYING)==1){
					orderRefund.set("state", OrderCode.RefundState.VERIFY_FAILED);
					orderRefund.set("refuseReason", refuseReason);
					//判断原订单状态当前如果是“已取消”，则将订单状态从“已取消”修改为“正常”
					Order order = orderService.getOrderByOrderNum(orderRefund.getStr("orderNum"));
					if(order.getInt("orderState")==OrderCode.OrderState.CANCEL){
						Db.update("UPDATE t_bus_order SET orderState=? WHERE orderNum=? AND orderState=?",OrderCode.OrderState.NORMAL,orderRefund.getStr("orderNum"),OrderCode.OrderState.CANCEL);
					}
					renderSuccess(orderRefund);
					return;
				}
			}
		}
		//其他情况
		renderFailed("操作失败");
		return;
	}
	
	/**
	 * 审核通过
	 */
	public void doAgree(){
		String refundNum = getPara("refundNum");
		if(StrKit.isBlank(refundNum)){
			renderResult(1);
			return;
		}else{
			OrderRefund orderRefund = service.getOrderRefundByOrderNum(refundNum);
			if(orderRefund==null){
				renderResult(2);
				return;
			}else{
				//修改退款单状态为审核通过
				if(Db.update("UPDATE t_bus_order_refund SET state=? WHERE refundNum=? AND state=?",OrderCode.RefundState.VERIFIED,refundNum,OrderCode.RefundState.VERIFYING)==1){
					orderRefund.set("state", OrderCode.RefundState.VERIFIED);
					renderSuccess(orderRefund);
					return;
				}
			}
		}
		//其他情况
		renderFailed("操作失败");
		return;
	}
	
	/**
	 * 微信退款，根据订单来源，选择开放平台或是公众号退款
	 * @return 1：退款单号为空，2：退款单不存在，3：状态不正确，4：微信支付申请失败
	 */
	public void doWXRefund(){
		//退款单号
		String refundNum = getPara("refundNum");
		if(StrKit.isBlank(refundNum)){
			renderResult(1);
			return;
		}else{
			OrderRefund orderRefund = service.getOrderRefundByOrderNum(refundNum);
			if(orderRefund==null){
				renderResult(2);
				return;
			}
			if(orderRefund.getInt("state")!=OrderCode.RefundState.VERIFIED){
				renderResult(3);
				return;
			}else{
				Order order = service.getOrderByOrderNum(orderRefund.getStr("orderNum"));
				//******开始退款流程******
				//1.订单来源，1：客户端，2：微信商城
				int from = order.getInt("from");
				//2.根据不同订单来源，选择微信公众号或开放平台对应的商户信息，以及相应所需要的商户证书存放地址
				String appid = null, mch_id = null, key = null, certPath = null, certPassword = null;
				if(from == OrderCode.OrderFrom.APP){
					//来源自APP，使用开放平台对应的商户信息退款
					appid = PropKit.get("weixinpay.open.appid");
					mch_id = PropKit.get("weixinpay.open.mch_id");
					key = PropKit.get("weixinpay.open.key");
					certPath = PathKit.getRootClassPath()+"/"+PropKit.get("weixinpay.open.cert");
					certPassword = PropKit.get("weixinpay.open.certPassword");
				}else if(from == OrderCode.OrderFrom.WXSELLER){
					//来源自微信商城，使用公众平台对应的商户信息退款
					appid = PropKit.get("weixinpay.mp.appid");
					mch_id = PropKit.get("weixinpay.mp.mch_id");
					key = PropKit.get("weixinpay.mp.key");
					certPath = PathKit.getRootClassPath()+"/"+PropKit.get("weixinpay.mp.cert");
					certPassword = PropKit.get("weixinpay.mp.certPassword");
				}
				//3.准备要退款的参数
				//微信订单号
				String tradeNo = order.getStr("tradeNo");
				//原订单号
				String orderNum = order.getStr("orderNum");
				//判断订单是否为合单处理
				String mergerNum = order.getStr("mergerNum");
				if(!StrKit.isBlank(mergerNum)){
					//如果有，则退款时使用合单号
					orderNum = mergerNum;
				}
				//原订单总金额，单位为分
				int totalFee = Double.valueOf(order.getDouble("amount")*100).intValue();
				//要退款金额，单位为分
				int refundFee = Double.valueOf(orderRefund.getDouble("amount")*100).intValue();
				//4.微信退款流程开始
				try {
					HttpsRequest request = new HttpsRequest(certPath,certPassword);
					//接口请求参数
					RefundReqData refundReqData = new RefundReqData(appid,mch_id,key,tradeNo,orderNum,refundNum,totalFee,refundFee);
					String requestStr = UtilKit.getXMLFromObject(refundReqData);
					//接口响应参数
					String responseStr = request.post(PropKit.get("weixinpay.refund"), refundReqData);
					RefundResData refundResData = (RefundResData) UtilKit.getObjectFromXML(responseStr, RefundResData.class);
					//记录日志
					new OrderRefundAPIRecord()
					.set("flag", 1)
					.set("refundNum", refundNum)
					.set("orderNum", orderNum)
					.set("payMethod", OrderCode.OrderPayMethod.WEIXIN)
					.set("sendContent", requestStr)
					.set("returnContent", responseStr).save();
					//返回退款请求结果
					if(refundResData.getReturn_code().equals("SUCCESS")&&refundResData.getResult_code().equals("SUCCESS")){
						orderRefund.set("state", OrderCode.RefundState.REFUNDED).update();
						renderResult(4,orderRefund);
						return;
					}
				} catch (UnrecoverableKeyException e) {
					e.printStackTrace();
				} catch (KeyManagementException e) {
					e.printStackTrace();
				} catch (NoSuchAlgorithmException e) {
					e.printStackTrace();
				} catch (KeyStoreException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
				//其他情况，退款失败
				renderResult(5);
				return;
			}
		}
	}
	
	/**
	 * 支付宝退款
	 * @return 1：退款单号为空，2：退款单不存在，3：状态不正确，4：支付宝申请退款返回HTML
	 */
	public void toAlipayPrepayRefund(){
		//退款单号
		String refundNum = getPara("refundNum");
		if(StrKit.isBlank(refundNum)){
			setAttr("flag", 1);
		}else{
			OrderRefund orderRefund = service.getOrderRefundByOrderNum(refundNum);
			if(orderRefund==null){
				setAttr("flag", 2);
			}
			if(orderRefund.getInt("state")!=OrderCode.RefundState.VERIFIED){
				renderResult(3);
				return;
			}else{
				Order order = service.getOrderByOrderNum(orderRefund.getStr("orderNum"));
				//******开始退款流程******
				//支付宝退款流程
				//批次号
				String batch_no = DatetimeKit.getFormatDate("yyyyMMdd")+DatetimeKit.getFormatDate("HHmmss");
				//必填，格式：当天日期[8位]+序列号[3至24位]，如：201008010000001
				
				//退款笔数
				String batch_num = "1";
				//必填，参数detail_data的值中，“#”字符出现的数量加1，最大支持1000笔（即“#”字符出现的数量999个）
				
				//退款详细数据
				//必填，支付宝交易号^退款金额^退款理由[#支付宝交易号^退款金额^退款理由[...]]
				//如："2016030521001004000219601588^0.01^协商退款"
				String detail_data = order.getStr("tradeNo")+"^"+orderRefund.getDouble("amount")+"^协商退款";
				
				//把请求参数打包成数组
				Map<String, String> sParaTemp = new HashMap<String, String>();
				//请求接口名称
				sParaTemp.put("service", "refund_fastpay_by_platform_pwd");
				//卖家支付宝帐户
				sParaTemp.put("seller_email", PropKit.get("alipay.seller_id"));
				//商户号
				sParaTemp.put("partner", PropKit.get("alipay.partner"));
				//字符集
				sParaTemp.put("_input_charset", PropKit.get("alipay.inputCharset"));
				//退款回调通知地址，可空
				sParaTemp.put("notify_url", PropKit.get("alipay.refund.notifyUrl"));
				//退款当天日期，格式：年[4位]-月[2位]-日[2位] 小时[2位 24小时制]:分[2位]:秒[2位]，如：2007-10-01 13:13:13
				sParaTemp.put("refund_date", DatetimeKit.getFormatDate("yyyy-MM-dd HH:mm:ss"));
				sParaTemp.put("batch_no", batch_no);
				sParaTemp.put("batch_num", batch_num);
				sParaTemp.put("detail_data", detail_data);
				
				//建立请求
				//renderHtml(AlipaySubmit.buildRequest(sParaTemp,"get","确认"));
				setAttr("flag", 4);
				setAttr("formHtml", AlipaySubmit.buildRequest(sParaTemp,"get","确认"));
			}
		}
		render("alipayRefund.jsp");
	}
	
	/**
	 * 支付宝退款结果通知
	 */
	@Clear
	public void refundNotify(){
		//获取支付宝POST过来反馈信息
		Map<String,String> params = new HashMap<String,String>();
		Map<String,String[]> requestParams = getParaMap();
		for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) {
			String name = iter.next();
			String[] values = requestParams.get(name);
			String valueStr = "";
			for (int i = 0; i < values.length; i++) {
				valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
			}
			//乱码解决，这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
			//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "gbk");
			params.put(name, valueStr);
		}
		//对参数进行验证
		if(AlipayNotify.verify(params)){//验证成功
			//获取支付宝的通知返回参数
			//批量退款数据中转账成功的笔数，后台处理退款时都是单笔处理，所以在此验证笔数只能等于1时表示退款成功
			String success_num = getPara("success_num");
			if(Integer.valueOf(success_num)==1){
				//批量退款数据中的详细信息
				//支付宝交易号^退款金额^处理结果$退费账号^退费账户ID^退费金额^处理结果
				//如："2010031906272929^80^SUCCESS$jax_chuanhang@alipay.com^2088101003147483^0.01^SUCCESS"
				String result_details = getPara("result_details");
				if(!StrKit.isBlank(result_details)){
					String[] result = result_details.split("\\^");
					String tradeNo = result[0];
					String returnCode = result[result.length-1];
					if(returnCode.equals("SUCCESS")){
						if(Db.update("UPDATE t_bus_order_refund SET state=? WHERE orderNum = (SELECT orderNum FROM t_bus_order bo WHERE tradeNo=?)",OrderCode.RefundState.REFUNDED,tradeNo)==1){
							renderText("success");
							return;
						}
					}
				}
			}
		}
		//验证失败
		renderText("fail");
		return;
	}
}
